# -*- coding:utf-8 -*-
import time

# @Time    : 2024/4/3 14:51
# @Author  : zengwenjia
# @Email   : zengwenjia@lingxi.ai
# @File    : tele_salas.py
# @Software: LLM_internal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
import expiringdict

from bot.insurance_planner_gpt.utils.user_info_util import WechatKnowledge
from bot.bot import Bot
import uuid
import asyncio
import copy
from bot.insurance_planner_gpt.agent.tele_wechat_agent.user_questioning import QuestioningDisputeResolution
from bot.insurance_planner_gpt.utils.conversation_process_util import ConversationProcessUtil
from bot.insurance_planner_gpt.agent.tele_wechat_agent.tele_wechat_skill import TeleWechatSkill
from bot.insurance_planner_gpt.agent.tele_wechat_agent.conversation_agent import Conversation
from common.log import logger
import pandas as pd

knowledge_base_query = WechatKnowledge()
dict_cache = expiringdict.ExpiringDict(max_len=1000000, max_age_seconds=300)
first_reply = '喂，您好。诶，你好，不好意思打扰您了，我是慧择保险网的。我们想提升您的咨询体验，现在给您服务升级为专属1对1的服务顾问，关于保险的任何问题都可以找我聊，那我这边用官方企业微信添加您，辛苦您那边操作同意一下好吧？'


class TeleWechatAssistant(Bot):
    def __init__(self):
        self.wechat_skill_utter_set = ""
        self.context = ""
        self.context_history = []
        self.conversation_history_str = ""
        self.role_name = "保险顾问"
        self.user_question_prompt = ""
        self.skill_choose_prompt = ""
        self.conversation_prompt = ""
        self.wechat_skill = ""
        self.user_question = ""

    async def get_user_question(self, session_id):
        answer_list = []
        if len(self.context) <= 1:
            self.user_question = "无"
        else:
            questioning_dispute_resolution = QuestioningDisputeResolution(self.role_name, self.conversation_history_str)
            self.user_question_prompt = questioning_dispute_resolution.prompt
            self.user_question = await questioning_dispute_resolution.achat_auto_llm(type="self")
            self.user_question = self.user_question.replace('"', '').strip()

            if ("无问题" not in self.user_question) and ("无" != self.user_question):
                queryStr = "用户问题：" + self.user_question
                similarity_knowledge = await knowledge_base_query.search_with_score(queryStr, top_k=8)
                if similarity_knowledge:
                    exact_match_num = 0
                    for item in similarity_knowledge:
                        if "用户问题" not in item.metadata:
                            continue
                        metadata = {}
                        keys = ['用户问题', '优先级', '话术', '动作标签']
                        for key in keys:
                            if key in item.metadata:
                                metadata[key] = item.metadata[key] if (not pd.isna(item.metadata[key])) else '无'
                        if queryStr in item.page_content:
                            exact_match_num += 1
                        if exact_match_num > 0 and (queryStr not in item.page_content):
                            # 如果有完全匹配的，就不再继续找其他的
                            continue
                        answer_list.append(metadata)
        self.knowledge_solution_set = answer_list

    async def get_wechat_skill(self, session_id):
        wechat_skill_utter_set = []
        if len(self.context) <= 1:
            # self.wechat_skill = "加企微"
            # wechat_skill_utter_set.append({'沟通策略': '加企微', '优先级': 1,
            #                                '话术': '喂，您好。诶，你好，不好意思打扰您了，我是慧择保险网的。我们想提升您的咨询体验，现在给您服务升级为专属1对1的服务顾问，关于保险的任何问题都可以找我聊，那我这边用官方企业微信添加您，辛苦您那边操作同意一下好吧？',
            #                                '动作标签': '无'})
            self.wechat_skill = "加企微"
            # wechat_skill_utter_set.append({'沟通策略': '询问产品意向', '优先级': 1,
            #                                '话术': '喂，您好，您好，您终于接电话啦，很久没跟您联系了，是这样的，慧择成立18周年，上线了很多高性价比产品，今天来电是想问下您最近在关注什么类型的保险产品呢？',
            #                                '动作标签': '无'})
            wechat_skill_utter_set.append({'沟通策略': '免费领取赠险', '优先级': 1,
                                           '话术': '喂，您好。诶，你好，不好意思打扰您了，我是慧择保险网的。我们想提升您的咨询体验，现在给您服务升级为专属1对1的服务顾问，关于保险的任何问题都可以找我聊，那我这边用官方企业微信添加您，辛苦您那边操作同意一下好吧？',
                                           '动作标签': '无'})
        else:
            skill_choose = TeleWechatSkill(self.role_name, self.conversation_history_str)
            self.skill_choose_prompt = skill_choose.prompt
            wechat_skill_name = await skill_choose.achat_auto_llm(type="self")
            wechat_skill_name = wechat_skill_name.strip()
            self.wechat_skill = wechat_skill_name

            queryStr = "沟通策略：" + self.wechat_skill
            similarity_knowledge = await knowledge_base_query.search_with_score(queryStr, top_k=20)

            if similarity_knowledge:
                exact_match_num = 0
                for item in similarity_knowledge:
                    if "沟通策略" not in item.metadata:
                        continue
                    metadata = {}
                    keys = ['沟通策略', '优先级', '话术', '动作标签']
                    for key in keys:
                        if key in item.metadata:
                            metadata[key] = item.metadata[key] if (not pd.isna(item.metadata[key])) else '无'
                    if item.page_content == queryStr:
                        exact_match_num += 1
                    if exact_match_num > 0 and item.page_content != queryStr:
                        # 如果有完全匹配的，就不再继续找其他的
                        continue
                    wechat_skill_utter_set.append(metadata)
        wechat_skill_utter_set = self.delete_duplicate_user_utter(wechat_skill_utter_set)
        self.wechat_skill_utter_set = wechat_skill_utter_set

    def delete_duplicate_user_utter(self, user_utter_set):
        if not user_utter_set:
            return []

        assistant_content_set = set()
        if not self.context_history:
            return user_utter_set
        if len(user_utter_set) == 1:
            return user_utter_set
        for assistant_content in self.context_history:
            if assistant_content['role'] == 'assistant':
                assistant_content = assistant_content['content']
                if assistant_content:
                    assistant_content_set.add(assistant_content)
        user_utter_set_new = []
        for user_utter in user_utter_set:
            flag = True
            for assistant_content in assistant_content_set:
                if user_utter['话术'] == assistant_content:
                    flag = False
                    break
            if flag:
                user_utter_set_new.append(user_utter)
        if user_utter_set_new:
            return user_utter_set_new
        else:
            return user_utter_set



    async def generate_reply(self, is_stream=False):
        conversation = Conversation(self.role_name,
                                    self.conversation_history_str,
                                    self.user_question,
                                    self.knowledge_solution_set,
                                    self.wechat_skill,
                                    self.wechat_skill_utter_set,
                                    )
        self.conversation_prompt = conversation.prompt
        message = await conversation.achat_auto_llm(type="self", is_stream=is_stream)
        return message

    async def async_reply(self, context, session_id, base_info, is_stream=False, date_time=int(time.time() * 1000)):
        if len(context) < 1:
            if not is_stream:
                return first_reply
            return self.stream_msg(first_reply)
        is_sensitive, sensitive_msg = self.check_is_sensitive(context, session_id)
        if is_sensitive:
            # 未处理非流式输出的情况
            if not is_stream:
                return sensitive_msg
            return self.stream_msg(sensitive_msg)
        is_quiet, quiet_msg = await self.check_user_is_quiet(context, session_id)
        if is_quiet:
            # 未处理非流式输出的情况
            if not is_stream:
                return quiet_msg
            return self.stream_msg(quiet_msg)
        else:
            self.context = context
            self.context_history = context
            self.conversation_history_str = ConversationProcessUtil.format_conversation_history(
                context, assistant_role_name=self.role_name)
            start_time = time.time()
            await asyncio.gather(self.get_user_question(session_id), self.get_wechat_skill(session_id))
            logger.info('[async_reply] 执行时间:{} sessionId:{} 用户问题 销售技巧并行执行时间:{}'
                        .format(date_time, session_id, (time.time() - start_time) * 1000))
            logger.info('[async_reply] 执行时间:{} sessionId:{} 用户问题prompt:{} 用户问题答案:{}'
                        .format(date_time, session_id, self.user_question_prompt, self.user_question))
            logger.info('[async_reply] 执行时间:{} sessionId:{} 销售技巧prompt:{} 销售技巧答案:{}'
                        .format(date_time, session_id, self.skill_choose_prompt, self.wechat_skill))
            is_voicemail, msg = await self.check_user_is_voicemail(session_id)
            if is_voicemail:
                if not is_stream:
                    return msg
                return self.stream_msg(msg)
            is_continuous_not_required, continuous_not_required_msg = self.check_continuous_not_required(session_id,
                                                                                                         context)
            if is_continuous_not_required:
                if not is_stream:
                    return continuous_not_required_msg
                return self.stream_msg(continuous_not_required_msg)
            is_continuous_wechat_skill, continuous_wechat_skill_msg = self.check_continuous_wechat_skill(session_id,
                                                                                                         context)
            if is_continuous_wechat_skill:
                if not is_stream:
                    return continuous_wechat_skill_msg
                return self.stream_msg(continuous_wechat_skill_msg)
            else:
                message = await self.generate_reply(is_stream=is_stream)
                logger.info(
                    '[async_reply] 执行时间:{} sessionId:{} 话术选择:{}'
                    .format(date_time, session_id, self.conversation_prompt))
            return message

    async def stream_msg(self, msg):
        result = ""
        for text_outputs in msg:
            result = result + text_outputs
            # ret = {
            #     'choices': [{'delta': {'content': text_outputs}}]
            # }
            ret = {
                "text": result,
                "error_code": 0
            }
            yield ret

    async def async_reply_text(self, context, session_id, base_info, is_stream=False):
        reply_result = {}
        is_sensitive, sensitive_msg = self.check_is_sensitive(context, session_id)
        if is_sensitive:
            # 未处理非流式输出的情况
            reply_result['reply_text'] = sensitive_msg
            reply_result['wechat_skill'] = self.conversation_prompt
            return reply_result
        is_quiet, quiet_msg = await self.check_user_is_quiet(context, session_id)
        if is_quiet:
            reply_result['reply_text'] = quiet_msg
            reply_result['wechat_skill'] = self.conversation_prompt
            return reply_result
        self.context = context
        self.context_history = context
        self.conversation_history_str = (ConversationProcessUtil
                                         .format_conversation_history(context, assistant_role_name=self.role_name))
        await asyncio.gather(self.get_user_question(session_id), self.get_wechat_skill(session_id))
        reply_result = {'user_question': self.user_question, 'knowledge_solution_set': self.user_question_prompt,
                        'wechat_skill_utter_set': self.skill_choose_prompt, 'wechat_skill_utter': self.wechat_skill}
        is_voicemail, msg = await self.check_user_is_voicemail(session_id)
        if is_voicemail:
            reply_result['reply_text'] = msg
            reply_result['wechat_skill'] = self.conversation_prompt
            return reply_result
        is_continuous_not_required, continuous_not_required_msg = self.check_continuous_not_required(session_id,
                                                                                                     context)
        if is_continuous_not_required:
            reply_result['reply_text'] = continuous_not_required_msg
            reply_result['wechat_skill'] = self.conversation_prompt
            return reply_result
        is_continuous_wechat_skill, continuous_wechat_skill_msg = self.check_continuous_wechat_skill(session_id,
                                                                                                     context)
        if is_continuous_wechat_skill:
            reply_result['reply_text'] = continuous_wechat_skill_msg
            reply_result['wechat_skill'] = self.conversation_prompt
            return reply_result
        message = await self.generate_reply(is_stream=is_stream)
        reply_result['reply_text'] = message
        reply_result['wechat_skill'] = self.conversation_prompt
        return reply_result

    ## 语音信箱的回复会啥要写hardcode？
    async def check_user_is_voicemail(self, session_id):
        if '语音信箱' == self.user_question:
            return True, '慧择给老客户送福利了，邀请您添加企业微信领免费的保险，后续还有更多活动，欢迎您在微信上关注。感谢您对慧择的支持，祝您生活愉快，再见。'
        else:
            return False, ''

    async def check_user_is_quiet(self, conversation_history, session_id):
        if len(conversation_history) == 0:
            return False, ''
        context_copy = copy.deepcopy(conversation_history)
        merged_data = [context_copy[0]]
        for item in context_copy[1:]:
            # 如果当前元素的role与结果列表中最后一个元素的role相同
            if item['role'] == merged_data[-1]['role']:
                # 合并content，用中文逗号拼接
                merged_data[-1]['content'] += '，' + item['content']
            else:
                # 如果role不同，则将当前元素添加到结果列表
                merged_data.append(item)
        user_replies = [reply.get('content') for reply in merged_data if reply.get('role') == 'user']
        if user_replies and user_replies[-1] == '@@quiet@@':
            # 连续静音次数：从列表末尾开始计算连续的'@@quiet@@'
            count_consecutive_quiet = 0
            for content in reversed(user_replies):
                if content == '@@quiet@@':
                    count_consecutive_quiet += 1
                else:
                    break

            # 根据静音的次数返回不同的结果
            if count_consecutive_quiet >= 3:
                return True, '那等您方便的时候我们再联系吧，祝您生活愉快，再见。'
            elif count_consecutive_quiet == 2:
                return True, '不好意思哦，刚没太听清，您说什么？'
            elif count_consecutive_quiet == 1:
                return True, '您好，您这边能听到吗?'
        return False, ''

    def check_is_sensitive(self, context, session_id):
        sensitive_list = ['举报', '报警', '报个警', '投诉', '违规', '违法', '涉黑', '要告你', '去告你', '诉讼',
                          '恶势力',
                          '专案组', '恐吓', '反催收联盟', '大V', '警察', '公安', '急救', '消防', '公安局', '一一零',
                          '一二零', '幺幺零', '幺二零']
        if context:
            for item in context:
                if any(keyword in item.get('content', '') for keyword in sensitive_list):
                    return True, '好的，那就先不打扰您了，再见。'
        return False, ''

    def check_continuous_not_required(self, session_id, context):
        is_true = False
        msg = ''
        try:
            if len(context) == 0:
                return False, ''
            if ("无问题" not in self.user_question) and ("无" != self.user_question):
                if '不需要' in self.user_question or '在忙' in self.user_question or '不想' in self.user_question or '拒绝' in self.user_question:
                    refuse_times = 0
                    for dialogue_info in context:
                        if dialogue_info.get('role', '') == 'assistant':
                            user_question = dialogue_info.get('user_question', '')
                            # 出现拒绝类标签计数，出现非拒绝类标签跳出循环
                            if '不需要' in user_question or '在忙' in user_question or '不想' in user_question or '拒绝' in user_question:
                                refuse_times += 1
                            if refuse_times >= 3:
                                break
                    if refuse_times >= 3:
                        is_true = True
                        msg = '那确实很遗憾了，很抱歉打扰到您，就不多打扰了。祝您生活愉快，再见。'
        except Exception as e:
            logger.info('[check_continuous_not_required]解析数据报错 sessionId:{} 对话记录:{} 问题识别:{}'
                        .format(session_id, self.context, self.user_question))
        finally:
            return is_true, msg

    def check_continuous_wechat_skill(self, session_id, context):
        is_true = False
        msg = ''
        try:
            if len(context) == 0:
                return False, ''
            if self.wechat_skill:
                refuse_times = 0
                for item in reversed(context):
                    if item.get('role', '') == 'assistant' and item.get('sales_skill_name', '') == self.wechat_skill:
                        refuse_times += 1
                        if refuse_times >= 5:
                            break
                if refuse_times >= 5:
                    is_true = True
                    msg = '那确实很遗憾了，很抱歉打扰到您，就不多打扰了。祝您生活愉快，再见。'
        except Exception as e:
            logger.info('[check_continuous_wechat_skill]解析数据报错 sessionId:{} 对话记录:{} 问题识别:{}'
                        .format(session_id, self.context, self.user_question))
        finally:
            return is_true, msg


if __name__ == '__main__':
    import os

    os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

    base_info = {}
    conversation_history = []
    while True:

        sessionId = str(uuid.uuid4())
        wechat_assistant = TeleWechatAssistant()
        result = asyncio.run(wechat_assistant.async_reply(conversation_history, sessionId, base_info))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result.replace('\n', '').replace(' ', '')
        conversation_history.append(conversation_dict)
        print(result)

        if '再见' in result:
            break
        user_input = input("请输入用户的对话：")
        conversation_dict = {}
        conversation_dict["role"] = "user"
        conversation_dict["content"] = user_input
        conversation_history.append(conversation_dict)
